*******************************************************************************
* Custom Control
*
* (C)  Copyright Apple Computer, Inc. 1988
* All rights reserved.
*
* by Keith Rollin
* July 8, 1988
*
* The Custom control is a rectangle with little knobs on the corners and
* sides. The knobs can be dragged to change the size of the rectangle.
* Clicking on the frame will allow you to move the whole thing.
*
* The application sample shows how to create and use the control. It is used
* to size and position a Simple Button control.
*
* Demo Index:
*
*
* Files: System macros and equates.
*        BoxCtrl.Stds.aii
*        BoxCtrl.DefProc.aii
*
*
* Modification History:
*
* Version 2.0       Kaar
*
*      July 8, 1988
*
*      First Release
*
*******************************************************************************
*                                                                    *
*             Apple IIGS Source Code Sampler, Volume I               *
*                                                                    *
*             Copyright (c) Apple Computer, Inc. 1988                *
*                       All Rights Reserved                          *
*                                                                    *
*            Written by Apple II Developer Tech Support              *
*                                                                    *
*                                                                    *
*                                                                    *
*  ----------------------------------------------------------------  *
*                                                                    *
*     This program and its derivatives are licensed only for         *
*     use on Apple computers.                                        *
*                                                                    *
*     Works based on this program must contain and                   *
*     conspicuously display this notice.                             *
*                                                                    *
*     This software is provided for your evaluation and to           *
*     assist you in developing software for the Apple IIGS           *
*     computer.                                                      *
*                                                                    *
*     DISCLAIMER OF WARRANTY                                         *
*                                                                    *
*     THE SOFTWARE IS PROVIDED "AS IS" WITHOUT                       *
*     WARRANTY OF ANY KIND, EITHER EXPRESS OR IMPLIED,               *
*     WITH RESPECT TO ITS MERCHANTABILITY OR ITS FITNESS             *
*     FOR ANY PARTICULAR PURPOSE.  THE ENTIRE RISK AS TO             *
*     THE QUALITY AND PERFORMANCE OF THE SOFTWARE IS WITH            *
*     YOU.  SHOULD THE SOFTWARE PROVE DEFECTIVE, YOU (AND            *
*     NOT APPLE OR AN APPLE AUTHORIZED REPRESENTATIVE)               *
*     ASSUME THE ENTIRE COST OF ALL NECESSARY SERVICING,             *
*     REPAIR OR CORRECTION.                                          *
*                                                                    *
*     Apple does not warrant that the functions                      *
*     contained in the Software will meet your requirements          *
*     or that the operation of the Software will be                  *
*     uninterrupted or error free or that defects in the             *
*     Software will be corrected.                                    *
*                                                                    *
*     SOME STATES DO NOT ALLOW THE EXCLUSION                         *
*     OF IMPLIED WARRANTIES, SO THE ABOVE EXCLUSION MAY              *
*     NOT APPLY TO YOU.  THIS WARRANTY GIVES YOU SPECIFIC            *
*     LEGAL RIGHTS AND YOU MAY ALSO HAVE OTHER RIGHTS                *
*     WHICH VARY FROM STATE TO STATE.                                *
*                                                                    *
*                                                                    *
**********************************************************************



                    mcopy BoxCtrl.macros
                    copy 2/ainclude/E16.Quickdraw
                    copy 2/ainclude/E16.Memory
                    copy 2/ainclude/E16.EVENT
                    copy 2/ainclude/E16.Control
                    copy 2/ainclude/E16.Window
                    copy 2/ainclude/E16.Dialog

*******************************************************************************
*
*    Equates used in this program.
*
*******************************************************************************
DPHandle            gequ 0              ; Handle to Tool Direct Page area
DPPointer           gequ DPHandle+4     ; Pointer to Tool Direct Page area
deref               gequ DPPointer+4    ; Temporary Handle dereference area
Ctl1Ptr             gequ deref+4
Ctl2Ptr             gequ Ctl1Ptr+4
Control1            gequ Ctl2Ptr+4
Control2            gequ Control1+4

ScreenMode          gequ Mode640        ; used for _QDStartup
ScreenWidth         gequ 640            ; used for _EMStartup


                    EJECT
*******************************************************************************
*
Main                start
*
* Description:      This is the main routine. It calls routines to Initialize
*                   the tools, initialize application specific data, run the
*                   main EventLoop, close the application, and close the tools.
*                   Then it calls the ProDOS Quit command.
*
*
* Inputs:           NONE
*
* Outputs:          NONE
*
* External Refs:
*                   Import InitTools
*                   Import InitApp
*                   Import EventLoop
*                   Import CloseApp
*                   Import CloseTools
*                   Import QuitParms
*
* Entry Points:     NONE
*
*******************************************************************************
                    using Globals

                    jsr InitTools
                    jsr InitApp

                    _ShowCursor

                    jsr EventLoop

                    jsr CloseApp
                    jsr CloseTools

                    _Quit QuitParms

                    end

                    EJECT
*******************************************************************************
*
Globals             data
*
* Description:      Holder of all of our data.
*
*
* Inputs:           N/A
*
* Outputs:          N/A
*
* External Refs:    
*                   Import doUpdate     ; to update windows
*
* Entry Points:
*                   Export QuitParms    ; used by Main
*
*******************************************************************************
*
* Standard global data
*
*******************************************************************************

TitleString         str 'Custom Control Example Program'
AutString           str 'By Keith Rollin Apple DTS (c)1988 Apple Computer'
VersString          str 'Version: 2.0'

MenuHeight          ds 2                ; Stored height of menu bar
MyID                ds 2                ; Application ID
MyDP                ds 2                ; My direct page storage

QuitFlag            ds 2
QuitParms           dc i4'0'            ; Pathname of next app
                    dc i2'$00'          ; flags

EventRecord         ANOP
EventWhat           ds 2
EventMessage        ds 4
EventWhen           ds 4
EventWhere          ds 4
EventModifiers      ds 2
TaskData            ds 4
TaskMask            dc i4'$0000FFFF'

                    EJECT
*******************************************************************************
*
* Application specific global data
*
*******************************************************************************

; This is a list of pointers to the text that is used to create our menus. It
; is used by InitApp to find all of the menu templates and use them to create
; our menubar. This loop loads MenuPtrLen-4 into an index, gets the
; corresponding menu template pointer in this table, and uses that in a
; NewMenu call. It then decrements the index by 4, and repeats the procees
; until the index is negative.

MenuPtr             dc i4'AppMenu'
                    dc i4'FileMenu'
                    dc i4'EditMenu'
MenuPtrLen          equ *-MenuPtr


; Menu list: menu items should be numbered consecutivly starting from 250.
; As a convention, use 256 as about and 257 as Quit.

AppMenu             dc c'$$@\N1',i1'$00'
                    dc c'--About Custom Control...\N256V',i1'$00'
                    dc c'.'
FileMenu            dc c'$$  File  \N2',i1'$00'
                    dc c'--Hide Sizer\N259',i1'$00'
                    dc c'--Show Sizer\N258D',i1'$00'
                    dc c'--Close\N255DV',i1'$00'
                    dc c'--Quit\N257*Qq',i1'$00'
                    dc c'.'
EditMenu            dc c'$$  Edit  \N3',i1'$00'
                    dc c'--Undo\N250*ZzVD',i1'$00'
                    dc c'--Cut\N251*XxD',i1'$00'
                    dc c'--Copy\N252*CcD',i1'$00'
                    dc c'--Paste\N253*VvD',i1'$00'
                    dc c'--Clear\N254D',i1'$00'
                    dc c'.'

theWindow           ds 4


WindowTitle         str '  Custom Control  '

Stripes             dc i2'$0000'        ; Black frame
                    dc i2'$0f00'        ; Inact TBcolor, Inact TColor, Tcolor
                    dc i2'$020f'        ; Pattern, Pattern color, BG color
                    dc i2'$0000'        ; Frame growbox unselcted/selected
                    dc i2'$00f0'        ; infobar color (white)

WindData            dc i2'WEnd-WindData'
                    dc i2'fTitle+fMove+fVis+fCtlTie'
                    dc i4'WindowTitle'  ; Ptr to title
                    dc i4'$0'           ; RefCon
                    dc i2'0,0,0,0'      ; Full Size (0= default)
                    dc i4'stripes'      ; Color Table Pointer
                    dc i2'0,0'          ; Vertical/Horizontal origin
                    dc i2'0,0'          ; Data area height, width
                    dc i2'0,0'          ; Max Cont height, width
                    dc i2'0,0'          ; Pixels to scroll vert'ly, horiz'ly
                    dc i2'0,0'          ; Pixels to page vert'ly, horiz'ly
                    dc i4'0'            ; Information bar refcon.
                    dc i2'0'            ; Info bar height
                    dc i4'0'            ; DefProc.
                    dc i4'0'            ; Routine to draw info. bar.
                    dc i4'doUpdate'     ; Routine to draw content.
                    dc i2'30,40,160,400'                    ; Size and position
                    dc i4'$FFFFFFFF'    ; Plane to put window up in (topmost).
                    dc i4'0'            ; Address of window record (0 to alloc)
WEnd                ANOP
                    end

                    EJECT
*******************************************************************************
*
InitApp             start
*
* Description:      Perform any application specific initialization.
*
* Inputs:           NONE
*
* Outputs:          NONE
*
* External Refs:
*                   Import BoxProc
*
* Entry Points:     NONE
*
*******************************************************************************
                    using Globals

                    stz QuitFlag

                    pha
                    pha
                    PushLong #WindData
                    _NewWindow
                    PullLong theWindow  ; Pull off the window pointer

; Create the two controls that we will be using in this demo. They are a
; custom control, and a simply button that will be resized and moved with
; the custom control. However, it is important that they be created in the
; right order. Since they will be lying right on top of each other, it is not
; apparent which one we want to select when we click on one of them. In cases
; like this, where a mouse click is on top of two controls, the Control
; Manager selects the one that was created first. So we create the custom
; control first.

                    pha                 ; space for result
                    pha
                    PushLong theWindow
                    PushLong #theRect
                    PushLong #0         ; no title
                    PushWord #%111      ; vis, int will drag, corners & edges
                    PushWord #$0503     ; Width = 5/Height = 3
                    PushLong #CtrlData  ; Pointer to additional data
                    PushLong #BoxProc   ; DefProc
                    PushLong #0         ; refcon
                    PushLong #0         ; std color table
                    _NewControl
                    PullLong Control1

; It is possible that the rectangle that was used to create the above
; control is no longer the rectangle that is being used. This is because
; of the feature that aligns the corners of the control to the grid.
; In order to make the next control fall inside of the above control, get
; the CtlRect from its record, and use that when creating the simple
; button below.

                    ldy #2              ; dereference the Control handle
                    lda [Control1],y    ; to get a pointer to the control
                    sta Ctl1Ptr+2       ; record into 'Ctl1Ptr'
                    lda [Control1]
                    sta Ctl1Ptr

                    ldy #oCtlRect+6     ; now copy the control's rectangle
                    ldx #6              ; into 'theRect'
loop0010            lda [Ctl1Ptr],y
                    sta theRect,x
                    dey
                    dey
                    dex
                    dex
                    bpl loop0010

; now that that is done, we can create the simple button control

                    pha                 ; space for result
                    pha
                    PushLong theWindow
                    PushLong #theRect
                    PushLong #Title
                    PushWord #0
                    PushWord #0
                    PushLong #0
                    PushLong #simpleProc
                    PushLong #0         ; refcon
                    PushLong #0         ; std color table
                    _NewControl
                    PullLong Control2

                    rts

theRect             dc i2'50,140,110,300'
Title               str 'Move/Resize Me'
CtrlData            dc i2'10'           ; min Y
                    dc i2'10'           ; min X
                    dc i2'100'          ; max Y
                    dc i2'200'          ; max X
                    dc i2'16'           ; grid Y
                    dc i2'32'           ; grid X
                    end

                    EJECT
*******************************************************************************
*
CloseApp            start
*
* Description:      Close down things. This disposes of all items and memory
*                   that we allocated.
*
*
* Inputs:           NONE
*
* Outputs:          NONE
*
* External Refs:    NONE
*
* Entry Points:     NONE
*
*******************************************************************************
                    using Globals

                    rts
                    end

                    EJECT
*******************************************************************************
*
EventLoop           start
*
* Description:      Main Event Loop. Handle things until user selects Quit.
*
*
* Inputs:           NONE
*
* Outputs:          NONE
*
* External Refs:
*                   Import MenuSelect
*                   Import ignore
*                   Import doUpdate
*                   Import InContent
*
* Entry Points:     NONE
*
*******************************************************************************
                    using Globals

maxEvent            equ wInactMenu

                    pha                 ; Push on space for TaskMaster result
                    PushWord #EveryEvent ; GetNextEvent mask
                    PushLong #EventRecord ; Pointer to Event Record
                    _TaskMaster

                    pla                 ; Get TaskMaster result
                    beq EventLoop       ; Remove if you want to use null events
                    cmp #maxEvent+1     ; is the event number in range?
                    bge EventLoop
                    asl A               ; Turn it into an index
                    tax
                    jsr (TaskTable,x)   ; Call appropriate event handler

                    lda QuitFlag        ; Quit selected?
                    beq EventLoop       ; no - keep looping

                    rts                 ; yes- leave the program

TaskTable           dc i2'Ignore'       ; 0 Null
                    dc i2'Ignore'       ; 1 MouseDown
                    dc i2'Ignore'       ; 2 MouseUp
                    dc i2'Ignore'       ; 3 KeyDown
                    dc i2'Ignore'       ; 4 undefined
                    dc i2'Ignore'       ; 5 AutoKey
                    dc i2'Ignore'       ; 6 Update
                    dc i2'Ignore'       ; 7 undefined
                    dc i2'Ignore'       ; 8 Activate
                    dc i2'Ignore'       ; 9 Switch
                    dc i2'Ignore'       ; 10 Desk accessory
                    dc i2'Ignore'       ; 11 Device driver
                    dc i2'Ignore'       ; 12 ap
                    dc i2'Ignore'       ; 13 ap
                    dc i2'Ignore'       ; 14 ap
                    dc i2'Ignore'       ; 15 ap
                    dc i2'Ignore'       ; TASK 0 indesk
                    dc i2'MenuSelect'   ; TASK 1 in menuBar
                    dc i2'Ignore'       ; TASK 2 in system window
                    dc i2'InContent'    ; TASK 3 in content
                    dc i2'Ignore'       ; TASK 4 in Drag
                    dc i2'Ignore'       ; TASK 5 in grow
                    dc i2'Ignore'       ; TASK 6 in goaway
                    dc i2'Ignore'       ; TASK 7 in zoom
                    dc i2'Ignore'       ; TASK 8 in info bar
                    dc i2'MenuSelect'   ; TASK 9 in special menu
                    dc i2'Ignore'       ; TASK 10 in NDA
                    dc i2'Ignore'       ; TASK 11 in frame
                    dc i2'Ignore'       ; TASK 12 in drop

                    end

                    EJECT
*******************************************************************************
*
MenuSelect          start
*
* Description:      This routine is called when TaskMaster returns a menu
*                   event. It takes the menu item that was hit and calculates
*                   an offset into the menu dispatch table. It then calls that
*                   routine and unhilites the menu when it is done.
*
* Inputs:           TaskData holds menu item selected.
*
* Outputs:          NONE
*
* External Refs:
*                   Import ignore
*                   Import doAbout
*                   Import doQuit
*                   Import Showsizer
*                   Import HideSizer
*
* Entry Points:     NONE
*
*******************************************************************************
                    using Globals

                    lda TaskData        ; Get the ID of the menu item selected.
                    sec                 ; Turn it into an index by subtracting
                    sbc #250            ; the starting ID number (25) and mul-
                    asl a               ; tiplying by 2 (each table entry con-
                    tax                 ; sists of 2 bytes).
                    jsr (menuTable,x)   ; Call the routine behind it.

                    PushWord #0         ; Routine done - unhilite the menubar.
                    PushWord taskData+2
                    _HiLiteMenu

                    rts

MenuTable           dc i2'Ignore'       ; undo
                    dc i2'Ignore'       ; cut
                    dc i2'Ignore'       ; copy
                    dc i2'Ignore'       ; paste
                    dc i2'Ignore'       ; clear
                    dc i2'Ignore'       ; close
                    dc i2'doAbout'
                    dc i2'doQuit'
                    dc i2'ShowSizer'
                    dc i2'HideSizer'
                    end

                    EJECT
*******************************************************************************
*
Ignore              start
*
* Description:      Called when I want to ignore an event.
*
*
* Inputs:           NONE
*
* Outputs:          NONE
*
* External Refs:    NONE
*
* Entry Points:     NONE
*
*******************************************************************************

                    rts
                    end

                    EJECT
*******************************************************************************
*
doUpdate            start
*
* Description:      Called by TaskMaster to update a window's contents.
*
*
* Inputs:           NONE
*
* Outputs:          NONE
*
* External Refs:    NONE
*
* Entry Points:     NONE
*
*******************************************************************************
                    using Globals
                    
                    pha
                    pha
                    _GetPort
                    _DrawControls

                    rtl
                    end

                    EJECT
*******************************************************************************
*
InContent           start
*
* Description:      Handle clicks within the content region of a window. In
*                   this demo, we want to see if we have clicked on either of
*                   the controls. We do this by calling FindControl. If
*                   FindControl tells us that we clicked on a control, then we
*                   want to track the actions of that control as we move the
*                   mouse. Calling TrackControl will do this until the use
*                   lift up on the mouse button. Finally, if the control we
*                   were tracking was the 'sizer' custom control, we want to
*                   resize/move the simple button that was associated with it.
*                   So we hide the button, change its bounding rectangle, and
*                   show it again in its new location.
*
*
* Inputs:           NONE
*
* Outputs:          NONE
*
* External Refs:    NONE
*
* Entry Points:     NONE
*
*******************************************************************************
                    using Globals
                    
                    pha
                    PushLong #theControl
                    PushLong EventWhere
                    PushLong theWindow
                    _FindControl
                    pla                 ; pull off the part code
                    bne TrackIt         ; hit a control
                    brl done

TrackIt             pha
                    PushLong EventWhere
                    PushLong #0         ; no action Proc
                    PushLong theControl
                    _TrackControl
                    pla

                    cmp #$A0            ; did we track the Sizer?
                    bne done            ; no, so don't move anything

                    PushLong Control2   ; hide the simple button
                    _HideControl

                    PushLong Control1   ; hide the Sizer
                    _HideControl

                    ldy #2              ; Get Control's pointer and put it
                    lda [Control1],y    ; into a Direct Page location
                    sta Ctl1Ptr+2
                    lda [Control1]
                    sta Ctl1Ptr         ; 'Ctl1Ptr' points to the Sizer.

                    ldy #2              ; Do the exact same thing with the
                    lda [Control2],y    ; simple button.
                    sta Ctl2Ptr+2       
                    lda [Control2]
                    sta Ctl2Ptr         ; 'Ctl2Ptr' points to the simple button

                    ldy #oCtlRect       ; Now copy the bounding rectangle of
loop                lda [Ctl1Ptr],y     ; the Sizer into the bounding rectangle
                    sta [Ctl2Ptr],y     ; of the button. When we next show the
                    iny                 ; button, it will have the same size
                    iny                 ; and location as the Sizer.
                    cpy #oCtlRect+8
                    bne loop

                    PushLong Control2   ; Now Show Them both
                    _ShowControl

                    PushLong Control1
                    _ShowControl

done                ANOP
                    rts

theControl          ds 4

                    end

                    EJECT
*******************************************************************************
*
ShowSizer           start
*
* Description:      Call _ShowControl to...well...uh, show the control. Disable
*                   the "Show Sizer" menu item and enable the "Hide Sizer" menu
*                   item.
*
*
* Inputs:           NONE
*
* Outputs:          NONE
*
* External Refs:    NONE
*
* Entry Points:     NONE
*
*******************************************************************************
                    using Globals

                    PushLong Control1
                    _ShowControl

                    PushWord #258       ; Disable the Show menu item
                    _DisableMItem

                    PushWord #259       ; Enable the Hide Menu item
                    _EnableMItem

                    rts
                    end


                    EJECT
*******************************************************************************
*
HideSizer           start
*
* Description:      Call _HideControl to hide the control. Enable the "Show
*                   Sizer" menu item and disable the "Hide Sizer" menu item.
*
*
* Inputs:           NONE
*
* Outputs:          NONE
*
* External Refs:    NONE
*
* Entry Points:     NONE
*
*******************************************************************************
                    using Globals

                    PushLong Control1
                    _HideControl

                    PushWord #258       ; Enable the Show menu item
                    _EnableMItem

                    PushWord #259       ; Disable the Hide Menu item
                    _DisableMItem

                    rts
                    end

                    copy BoxCtrl.Std.src
                    copy DefProc.1.src
                    copy DefProc.2.src

                    END
